package com.vhdadw.service.impl;

import com.vhdadw.config.RabbitMQConfig;
import com.vhdadw.constant.TimeConstant;
import com.vhdadw.controller.request.ConfirmOrderRequest;
import com.vhdadw.controller.request.ProductOrderPageRequest;
import com.vhdadw.enums.*;
import com.vhdadw.exception.BizException;
import com.vhdadw.interceptor.LoginInterceptor;
import com.vhdadw.manager.ProductManager;
import com.vhdadw.manager.ProductOrderManager;
import com.vhdadw.model.EventMessage;
import com.vhdadw.model.LoginUser;
import com.vhdadw.model.ProductDO;
import com.vhdadw.model.ProductOrderDO;
import com.vhdadw.service.ProductOrderService;
import com.vhdadw.utils.CommonUtil;
import com.vhdadw.utils.JsonData;
import com.vhdadw.utils.JsonUtil;
import com.vhdadw.vo.PayInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ProductOrderServiceImpl implements ProductOrderService {

    @Autowired
    ProductOrderManager productOrderManager;

    @Autowired
    ProductManager productManager;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Override
    public Map<String, Object> page(ProductOrderPageRequest productOrderPageRequest) {

        Long accountNo = LoginInterceptor.threadLocal.get().getAccountNo();

        Map<String, Object> pageResult = productOrderManager.page(
                productOrderPageRequest.getPage(),
                productOrderPageRequest.getSize(),
                accountNo,
                productOrderPageRequest.getState());
        return pageResult;
    }

    @Override
    public String queryProductOrderState(String outTradeNo) {

        Long accountNo = LoginInterceptor.threadLocal.get().getAccountNo();

        ProductOrderDO productOrderDO = productOrderManager.findByOutTradeNoAndAccount(outTradeNo, accountNo);

        if (productOrderDO == null) {
            return "";
        } else {
            return productOrderDO.getState();
        }
    }

    /**
     * 防重提交（TODO）
     * 获取最新的流量包价格
     * 订单验价
     * 如果有优惠券或者其他抵扣
     * 验证前端显示和后台计算价格
     * 创建订单对象保存数据库
     * 发送延迟消息-⽤于⾃动关单（TODO）
     * 创建⽀付信息-对接三⽅⽀付（TODO）
     * 回调更新订单状态（TODO）
     * ⽀付成功创建流ᰁ包（TODO）
     *
     * @param orderRequest
     * @return
     */
    @Override
    @Transactional
    public JsonData confirmOrder(ConfirmOrderRequest orderRequest) {

        LoginUser loginUser = LoginInterceptor.threadLocal.get();

        String orderOutTradeNo = CommonUtil.getStringNumRandom(32);

        ProductDO productDO = productManager.findDetailById(orderRequest.getProductId());

        //验证价格
        this.checkPrice(productDO, orderRequest);

        //创建订单
        ProductOrderDO productOrderDO = this.saveProductOrder(orderRequest, loginUser, orderOutTradeNo, productDO);

        //创建支付对象
        PayInfoVO payInfoVO = PayInfoVO.builder().accountNo(loginUser.getAccountNo())
                .outTradeNo(orderOutTradeNo).clientType(orderRequest.getClientType())
                .payType(orderRequest.getPayType()).title(productDO.getTitle())
                .description(productDO.getDetail()).payFee(orderRequest.getPayAmount())
                .orderPayTimeoutMills(TimeConstant.ORDER_PAY_TIMEOUT_MILLS).build();

        //发送延迟消息（超时关单） TODO
        EventMessage eventMessage = EventMessage.builder()
                .eventMessageType(EventMessageType.PRODUCT_ORDER_NEW.name())
                .accountNo(loginUser.getAccountNo())
                .bizId(orderOutTradeNo)
                .build();

        rabbitTemplate.convertAndSend(rabbitMQConfig.getOrderEventExchange(),rabbitMQConfig.getOrderCloseDelayRoutingKey(),eventMessage);


        //调用支付信息 TODO
//        Map<String, String> paramsMap = new HashMap<>(3);
//
//        paramsMap.put("out_trade_no", orderOutTradeNo);
//        //交易状态
//        paramsMap.put("trade_state", "SUCCESS");
//        //用户编号
//        paramsMap.put("account_no", String.valueOf(loginUser.getAccountNo()));
//
//        this.processOrderCallbackMsg(ProductOrderPayTypeEnum.WECHAT_PAY,paramsMap);

        return JsonData.buildSuccess();
    }

    @Override
    public boolean closeProductOrder(EventMessage eventMessage) {

        //订单状态判断
        String outTradeNo = eventMessage.getBizId();
        Long accountNo = eventMessage.getAccountNo();

        ProductOrderDO productOrderDO = productOrderManager.findByOutTradeNoAndAccount(outTradeNo, accountNo);

        if(productOrderDO==null){

            //订单不存在
            log.error("订单不存在");
            return true;

        }

        if(productOrderDO.getState().equalsIgnoreCase(ProductOrderStateEnum.PAY.name())){
            //已支付
            log.info("直接确认消息，订单已支付：{}",eventMessage);
            return true;
        }

        //未支付，需要向第三方支付平台查询状态
        if(productOrderDO.getState().equalsIgnoreCase(ProductOrderStateEnum.NEW.name())){
            //向第三方查询状态
            PayInfoVO payInfoVO = new PayInfoVO();
            payInfoVO.setPayType(productOrderDO.getPayType());
            payInfoVO.setOutTradeNo(outTradeNo);
            payInfoVO.setAccountNo(accountNo);

            //TODO 查询 向第三方查询状态
            String payResult ="";
            if(StringUtils.isBlank(payResult)){
                //如果为空，则未支付成功，取消本地订单
                productOrderManager.updateOrderPayState(outTradeNo,accountNo,ProductOrderStateEnum.CANCEL.name(), ProductOrderStateEnum.NEW.name());
                log.info("未支付成功，本地取消订单：{}",eventMessage);
            }else{

                //支付成功，主动将订单状态更新为支付
                log.warn("支付成功，支付回调信息失败，需要排查：{}",eventMessage);
                productOrderManager.updateOrderPayState(outTradeNo,accountNo,ProductOrderStateEnum.PAY.name(), ProductOrderStateEnum.NEW.name());

                //触发支付后逻辑 TODO
            }
        }
        return true;
    }


    /**
     * 处理微信回调通知
     * @param payType
     * @param paramsMap
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public JsonData processOrderCallbackMsg(ProductOrderPayTypeEnum payType, Map<String, String> paramsMap) {

        //获取商户订单号
        String outTradeNo = paramsMap.get("out_trade_no");
        //交易状态
        String tradeState = paramsMap.get("trade_state");
        //用户编号
        Long accountNo = Long.valueOf(paramsMap.get("account_no"));

        ProductOrderDO productOrderDO = productOrderManager.findByOutTradeNoAndAccount(outTradeNo, accountNo);

        Map<String, Object> content = new HashMap<>(4);
        content.put("outTradeNo",outTradeNo);
        content.put("buyNum",productOrderDO.getBuyNum());
        content.put("accountNo",accountNo);
        content.put("product",productOrderDO.getProductSnapshot());

        //构建消息
        EventMessage eventMessage = EventMessage.builder()
                .bizId(outTradeNo)
                .accountNo(accountNo)
                .messageId(outTradeNo)
                .content(JsonUtil.obj2Json(content))
                .eventMessageType(EventMessageType.PRODUCT_ORDER_PAY.name())
                .build();

        if(payType.name().equalsIgnoreCase(ProductOrderPayTypeEnum.ALI_PAY.name())){
            //支付宝支付逻辑 TODO
        } else if (payType.name().equalsIgnoreCase(ProductOrderPayTypeEnum.WECHAT_PAY.name())) {
            //支付成功
            if("SUCCESS".equalsIgnoreCase(tradeState)){

                //key不存在，则设置成功，返回true
                Boolean flag = redisTemplate.opsForValue().setIfAbsent(outTradeNo,"OK",3, TimeUnit.DAYS);

                if(flag){
                    rabbitTemplate.convertAndSend(rabbitMQConfig.getOrderEventExchange(),
                            rabbitMQConfig.getOrderUpdateTrafficRoutingKey(),eventMessage);
                    return JsonData.buildSuccess();
                }

            }
        }
        return JsonData.buildResult(BizCodeEnum.PAY_ORDER_CALLBACK_SIGN_FAIL);
    }

    @Override
    public void handleProductOrderMessage(EventMessage eventMessage) {

        String messageType =  eventMessage.getEventMessageType();

        try{

            if(EventMessageType.PRODUCT_ORDER_NEW.name().equalsIgnoreCase(messageType)){

                //新建订单状态 进入  为关闭订单操作
                //关闭订单
                this.closeProductOrder(eventMessage);
            }else if(EventMessageType.PRODUCT_ORDER_PAY.name().equalsIgnoreCase(messageType)){
                //订单已支付，更新订单状态
                String outTradeNo = eventMessage.getBizId();
                Long accountNo = eventMessage.getAccountNo();
                int rows = productOrderManager.updateOrderPayState(outTradeNo,accountNo,ProductOrderStateEnum.PAY.name(),
                        ProductOrderStateEnum.NEW.name());
                log.info("订单更新成功：rows={},eventMessage={}",rows,eventMessage);
            }


        }catch (Exception e){
            log.error("订单消费者消费失败：{}",eventMessage);
            throw new  BizException(BizCodeEnum.MQ_CONSUMER_EXCEPTION);
        }

    }


    private ProductOrderDO saveProductOrder(ConfirmOrderRequest orderRequest, LoginUser loginUser, String orderOutTradeNo, ProductDO productDO) {

        ProductOrderDO productOrderDO = new ProductOrderDO();

        //设置用户信息
        productOrderDO.setAccountNo(loginUser.getAccountNo());
        productOrderDO.setNickname(loginUser.getUsername());

        //设置商品信息
        productOrderDO.setProductId(productDO.getId());
        productOrderDO.setProductTitle(productDO.getTitle());
        productOrderDO.setProductSnapshot(JsonUtil.obj2Json(productDO));
        productOrderDO.setProductAmount(productDO.getAmount());

        //设置订单信息
        productOrderDO.setBuyNum(orderRequest.getBuyNum());
        productOrderDO.setOutTradeNo(orderOutTradeNo);
        productOrderDO.setCreateTime(new Date());


        //发票信息
        productOrderDO.setBillType(BillTypeEnum.valueOf(orderRequest.getBillType()).name());
        productOrderDO.setBillHeader(orderRequest.getBillHeader());
        productOrderDO.setBillReceiverPhone(orderRequest.getBillReceiverPhone());
        productOrderDO.setBillReceiverEmail(orderRequest.getBillReceiverEmail());
        productOrderDO.setBillContent(orderRequest.getBillContent());


        //实际支付总价
        productOrderDO.setPayAmount(orderRequest.getPayAmount());
        //总价（未使用优惠券）
        productOrderDO.setTotalAmount(orderRequest.getTotalAmount());
        //订单状态
        productOrderDO.setState(ProductOrderStateEnum.NEW.name());
        //支付类型
        productOrderDO.setPayType(ProductOrderPayTypeEnum.valueOf(orderRequest.getPayType()).name());

        //插入数据库
        productOrderManager.add(productOrderDO);

        return productOrderDO;
    }

    private void checkPrice(ProductDO productDO, ConfirmOrderRequest orderRequest) {

        //后台计算价格
        BigDecimal bizTotal = BigDecimal.valueOf(orderRequest.getBuyNum()).multiply(productDO.getAmount());

        //前后端总价对比
        if (bizTotal.compareTo(orderRequest.getPayAmount()) != 0) {
            log.error("验证价格失败：{}", orderRequest);
            throw new BizException(BizCodeEnum.ORDER_CONFIRM_PRICE_FAIL);
        }

    }

}
